<template>
  <!-- Monica图  -->
  <div id="QcMonicaChart">
    <Splitpanes horizontal>
      <Pane size="66">
        <el-scrollbar style="height: 100%; width: 100%">
          <div id="monicachart">
            <div
              ref="piechart"
              id="M-chartMain"
              :style="{
                width: '100%',
                height: '500px'
              }"
              v-show="chartData"
              v-loading="loading"
            ></div>
          </div>
        </el-scrollbar>
      </Pane>
      <Pane size="34">
        <vxe-table
          ref="monicaTable"
          v-loading="loading"
          border
          align="center"
          class="mytable-scrollbar bottomTable"
          height="auto"
          :data="chartData.results"
          :row-config="{ isCurrent: true, isHover: true }"
          :keyboard-config="{
            isArrow: true,
            isTab: true,
            isEdit: true
          }"
          resizable
          show-overflow
        >
          <vxe-column field="n" title="序号" width="30" header-align="center"></vxe-column>
          <vxe-column field="qcDate" title="检测日期" width="100">
            <template #default="{ row }">
              <span>{{ formatDateTime(row.qcDate, 'yyyy-MM-dd') }}</span>
            </template>
          </vxe-column>

          <vxe-column field="mean" title="mean" width="70" header-align="center" align="right">
            <template #default="{ row }">
              <span>{{ row.mean ? parseFloat(row.mean).toFixed(3) : '' }}</span>
            </template>
          </vxe-column>
          <vxe-colgroup title="最大值" header-align="center">
            <vxe-column
              field="qcSequence"
              title="次数"
              width="60"
              header-align="center"
              align="right"
            >
              <template #default="{ row }">
                <span>{{ row.max ? row.max.qcSequence : '' }}</span>
              </template>
            </vxe-column>
            <vxe-column field="result" title="结果" width="90" header-align="center" align="right">
              <template #default="{ row }">
                <span>{{ row.max ? row.max.result : '' }}</span>
              </template>
            </vxe-column>
          </vxe-colgroup>
          <vxe-colgroup title="最小值" header-align="center">
            <vxe-column
              field="qcSequence"
              title="次数"
              width="60"
              header-align="center"
              align="right"
            >
              <template #default="{ row }">
                <span>{{ row.min ? row.min.qcSequence : '' }}</span>
              </template>
            </vxe-column>
            <vxe-column field="result" title="结果" width="90" header-align="center" align="right">
              <template #default="{ row }">
                <span>{{ row.min ? row.min.result : '' }}</span>
              </template>
            </vxe-column>
          </vxe-colgroup>
          <vxe-column title="状态" width="60" align="center">
            <template #default="{ row }">
              <span
                :style="{
                  color: row.isAlarm ? '#e6a23c' : row.isOutControl ? 'red' : ''
                }"
              >
                {{ row.isAlarm ? '警告' : row.isOutControl ? '失控' : '在控' }}
              </span>
            </template>
          </vxe-column>
        </vxe-table>
      </Pane>
    </Splitpanes>
    <vxe-modal
      v-model="modalShow"
      id="MonicaTip"
      width="80%"
      height="80%"
      min-width="460"
      min-height="320"
      show-footer
      show-zoom
      resize
    >
      <template #title>
        <span>Monica图例说明</span>
      </template>
      <template #default>
        <div>
          <p>
            改良Monica质控图用于室内常规项目的质控，能同时监测精密度和准确度，及时指示存在的误差大小和性质，制作简便，应用及时，形象直观，能将室内质控和室间质评有机地直接联系起来，从质控图上就可基本预测参加室间质评的变异指数得分情况。
          </p>
          <p>
            制作Monica质控图时，需要在进行病人标本常规测定中，插入两份质控血清同时操作，将此两个测定值点在质控图上，用垂线将此两点连接，再用标出垂线的中点（代表双份测定的均值），然后用线将相邻的中点连起来。在纵轴居中绘出平行于横轴的靶值（target
            value，T）线，并绘出上下警告值线（warning line）和最大允许值线（max
            error）4条平行于靶值线的直线。警告值线和最大允许值线用一定范围的选定的变异系数（chosen
            coefficient variation，CCV）来确定。具体的CCV值需要根据国家室间质评项目的要求来设置。
          </p>
          <p>
            在质控图中采用0.8CCV和1.5CCV作为误差界限的目的是试图将室内质控和室间质评更为有机地直接联系起来。根据变异指数（Variance
            Index，VI）的计算公式：
          </p>
          <p>VI＝〔(|X－T|)×100/T〕×100/CCV</p>
          <p>
            式中(|X－T|)/T是测定值的相对误差，用d表示，则：VI＝d×100/CCV，若设定VI＝80时，则d＝0.8CCV。
          </p>
          <p>
            因此，对一个测定结果，当VI≤80时，则d≤0.8CCV；当80＜VI≤150时，则0.8CCV＜d≤1.5CCV；当VI＞150时，则d＜1.5CCV；同理，当d≤0.8CCV时，则VI≤80，即测定结果的相对误差不大于0.8CCV时，VI值也不会大于80，则VIS也不会大于80，在室间质评中成绩为优秀；当0.8CCV＜d≤1.5CCV时，则80＜VI≤150，即测定结果的相对误差不大于1.5CCV时，VIS也不会大于150，在室间质评中为及格；如果d＞1.5CCV，则VI＞150，即测定结果的相对误差大于1.5CCV时，VIS就在150以上。在室间质评中不及格。
          </p>
          <p>
            由此可见，用Monica质控图进行室内质控，如能做到全部测定结果中点落在警告线内，参加室间质评可获得优秀成绩；如果有些中点分布在警告线外，但在最大允许线内，参加室间质评可望及格；如果经常出现超出最大允许线的中点，参加室间质评很难达到及格。
          </p>
          <p>
            按照Monica判断标准，最理想的结果是质控血清的全部测定值（不是双份测定的均值）都落在警告线内。如果超出警告线，但仍在最大允许线内，该批病人标本测定结果仍然有效，即“在控”，但指示测定误差较大，须仔细检查可能产生误差的各个环节。出现任何落在最大允许线外的点都表示“失控”，该批测定结果无效，应查明误差原因并予消除后重新测定。
          </p>
          <p>
            在Monica质控图中，由于相邻各红点连线与X-S质控图相似，因此，X-S质控图的分析判断标准也基本适用Monica质控图。
          </p>
          <p>
            在Monica质控图中，双份重复测定值的垂线的长短可作为精密度的指示，愈短精密度愈好，愈长则愈差。中点离靶值线的远近可作为准确度的指示，离得愈近，准确度愈好，愈远则愈差。可根据垂线的长短和中点的位置，分析判断该批测定结果的精密度和准确度及其误差的大小和性质。
          </p>
        </div>
      </template>
    </vxe-modal>
  </div>
</template>
<script setup lang="ts">
import { Ref, ref, defineExpose, reactive, getCurrentInstance, onMounted } from 'vue';
import { ECharts, EChartsOption, init } from 'echarts';
import { formatDateTime, IsEmpty } from '@/utils/common';
import { Splitpanes, Pane } from 'splitpanes';

defineExpose({
  getEchartData
});

// 变量定义区
let { proxy }: any = getCurrentInstance();
const piechart: Ref<HTMLElement | null> = ref(null);
const chartHeight = ref('');
const resultForm = reactive({
  rptGroupId: null, //报告单元id
  rptGroupName: '',
  // selectWorkTeam: '', //选中的子工作组id
  insId: null, //仪器
  insName: '',
  insAnsId: null, //仪器项目
  itemDictId: null, //项目
  ansName: '',
  iqcMaterialIds: [],
  QCDateS: null, //开始时间
  QCDateE: null, //结束时间
  ccv: null
});
const chartData = reactive({
  t: null,
  ccv: null,
  results: []
});
let modalShow = ref(false);

// 方法定义区
function getEchartData(iqcResultForm: any, height: any, ccv: any) {
  chartHeight.value = height;
  Object.assign(resultForm, iqcResultForm);

  resultForm.ccv = ccv;
  if (resultForm.iqcMaterialIds.length === 0) {
    Object.assign(chartData, {});
    clearCanvas();
    return;
  }

  let url = '/api/qc/chart/getMonicaData';
  let obj = {
    itemDictId: resultForm.itemDictId,
    QcMaterialIds: resultForm.iqcMaterialIds,
    QCDateS: resultForm.QCDateS,
    QCDateE: resultForm.QCDateE,
    ccv: resultForm.ccv
  };
  proxy.$http
    .get(url, { params: obj })
    .then((res: any) => {
      if (res.data.results && res.data.results.length > 0) {
        Object.assign(chartData, res.data);
        initChart(chartData);
      } else {
        chartData.results.length = 0;
        clearCanvas();
      }
    })
    .catch((err) => {
      proxy.$alert(err, '提示');
      // this.loading = false;
    });
}

// 清除画布
function clearCanvas() {
  const myChart = init(piechart.value as HTMLElement);
  myChart.clear(); // 清除画布
}

function initChart(val) {
  // 图表宽度自适应
  const chartBox = document.getElementById('monicachart');
  const chartDom = document.getElementById('M-chartMain');
  //图表宽高计算
  //   this.chartssize(chartBox, chartDom);
  // const myChart = echarts.init(chartDom);
  const myChart = init(piechart.value as HTMLElement);
  //   this.chart = myChart;

  const ccv = val.ccv;
  const t = val.t;

  const yAxisData = [
    t - 3 * ccv * t,
    t - 1.5 * ccv * t,
    t - 0.8 * ccv * t,
    t,
    t + 0.8 * ccv * t,
    t + 1.5 * ccv * t,
    t + 3 * ccv * t
  ];
  const xAxisData = [];
  const meanData = []; //均值折线点
  const seriesData = []; //柱状图的差值（画垂直线）
  const minData = [];
  const maxData = [];
  const minScatterData = []; //垂直线下端的点
  const maxScatterData = []; //垂直线上端的点
  const yColor = [];
  for (let i = 0; i <= 60; i++) {
    if (i === 0) {
      yColor.push('#ddd');
    } else {
      yColor.push('transparent');
    }
  }
  val.results.forEach((item, index) => {
    xAxisData.push(item.n);
    meanData.push({
      qcDate: item.qcDate,
      n: item.n,
      value: item.mean
    });
    minData.push(item.min.numResult);
    maxData.push(item.max.numResult);
    seriesData.push(parseFloat(item.max.numResult) - parseFloat(item.min.numResult));

    minScatterData.push({
      itemStyle: {
        color: item.isAlarm ? '#e6a23c' : item.isOutControl ? 'red' : '#46b830'
      },
      value: [item.n - 1, item.min.numResult]
    });
    maxScatterData.push({
      itemStyle: {
        color: item.isAlarm ? '#e6a23c' : item.isOutControl ? 'red' : '#46b830'
      },
      value: [item.n - 1, item.max.numResult]
    });
  });

  const option = {
    title: {
      // text: '',
    },
    legend: {
      type: 'scroll',
      top: 10,
      itemWidth: 35,
      textStyle: {
        fontSize: 16
      }
    },
    tooltip: {
      trigger: 'axis',
      axisPointer: {
        // type: 'line',//指示器
      },
      confine: true, //是否将 tooltip 框限制在图表的区域内
      backgroundColor: 'rgba(255, 255, 255, 0.8)',
      borderRadius: 5,
      extraCssText: 'box-shadow: 0 0 3px rgba(0, 0, 0, 0.3);',
      padding: [5, 10],
      textStyle: {
        color: '#333'
      },
      formatter: formatter
    },
    toolbox: {
      feature: {
        saveAsImage: {
          title: '保存为图片',
          name: 'Monica图-' + formatDateTime(new Date(), 'yyyy-MM-dd'),
          type: 'png'
        },
        myTipImage: {
          //自定义图标，必须以my开头
          show: true,
          title: 'Monica图说明',
          icon: 'path://M505.3 844.6c-6.8 0-13.9-2-19.8-5.7-6.7-4.1-11.7-8.9-14.8-14.2-3.5-6.5-5.2-13.2-5.2-20 0-11.8 3.7-21.3 11.3-28.9 8.5-7.5 17.6-10.9 28.6-10.9 11.9 0 21.2 3.5 28.5 10.8 7.6 7.6 11.4 17.1 11.4 29 0 7.3-1.7 14-5.2 19.9-3.4 5.9-8.2 10.5-14.7 14.2-6.8 3.9-13.5 5.8-20.1 5.8z m-2.8-146.8c-9.3-1.4-16.2-5.2-21.8-11.7-5.4-6.3-7.9-14.1-7.4-23.7 3.7-28.8 14-54.3 31.6-77.9 16.3-23 37-46.4 63.3-71.6l0.1-0.1c37.4-37.9 61-66.7 70.2-85.7 9.1-18.7 12.9-35.2 11.4-48.9 1.5-33.6-9.9-63.6-34-89.3-13.4-14-28.9-24.7-47.3-32.8-18.3-7.5-37.2-11.3-56.5-11.3-39.3 0.5-71.3 13.7-97.9 40.3-25.2 25.7-38.7 58.2-40.3 96.7v0.2c0 9.6-3.1 17.7-9.3 23.8-6.2 6.2-14 9.3-23.3 9.3-9.9 0-17.5-3-23.2-9.2l-0.1 0.1c-6.1-6.1-9.3-13.9-9.8-23.9 0-27.3 5.2-53.3 15.3-77.2 10.1-24.2 24.7-45.7 44.6-65.6 19.9-19.9 41.4-34.5 65.6-44.6 24.8-10.3 50.1-15.4 77.3-15.4 28.7 0 56.6 5.5 83.1 16.4 26 10.7 49.2 26.7 69.1 47.6 18.8 18.8 32.7 40.3 41.5 63.9 8.7 23.4 12.3 48.5 10.7 74.6v0.4c0.5 21.5-5.2 44.9-17.4 71.3-12.1 25.7-40.1 61.2-83.3 105.4-23.3 22.7-40.8 42-53.6 58.9-13 17.2-20.5 34.1-22.2 50.4-1.5 9-4.9 15.7-10.8 21.1-6 5.5-13.3 8.3-21.8 8.3h-3.8z',
          onclick: () => {
            modalShow.value = true;
          }
        }
      },
      right: 20
    },
    grid: {
      top: '50px',
      bottom: '70px',
      left: '80px',
      right: '50px'
    },
    xAxis: {
      type: 'category',
      boundaryGap: false,
      splitLine: {
        show: true
      },
      axisLine: {
        show: false
      },
      axisLabel: {
        interval: 0
      }, //强制显示所有坐标
      data: xAxisData
    },
    yAxis: [
      {
        name: 'T:' + t.toFixed(3) + ' CCV:' + ccv.toFixed(3),
        type: 'value',
        nameTextStyle: {
          color: '#f56c6c'
        },
        data: yAxisData,
        max: yAxisData[yAxisData.length - 1], //坐标轴刻度最大值
        min: yAxisData[0],
        splitNumber: yAxisData.length, //坐标轴的分割段数
        axisTick: {
          show: false
        },
        interval: 0.1 * ccv * t,
        splitLine: {
          show: true,
          lineStyle: {
            // 使用深浅的间隔色
            color: yColor
          }
        },
        axisLabel: {
          formatter: function (v, ix) {
            let value = '';
            if (ix === 15) {
              value = 'T-1.5CCV*T';
            } else if (ix === 22) {
              value = 'T-0.8CCV*T';
            } else if (ix === 30) {
              value = 'T';
            } else if (ix === 38) {
              value = 'T+0.8CCV*T';
            } else if (ix === 45) {
              value = 'T+1.5CCV*T';
            }
            return value;
          }
        }
      }
    ],
    dataZoom: [
      {
        type: 'slider',
        start: 0,
        end: 100,
        height: 18,
        filterMode: 'empty',
        showDataShadow: false
      },
      {
        type: 'inside',
        start: 0,
        end: 100
      }
    ], //区域缩放
    series: [
      {
        name: 'mean',
        type: 'line',
        data: meanData,
        connectNulls: true, //断点链接
        color: '#409eff',
        yAxisIndex: 0,
        markLine: {
          symbol: 'none',
          silent: true,
          lineStyle: { normal: { type: 'solid' } },
          label: { position: 'start' },
          data: [
            {
              yAxis: yAxisData[1],
              lineStyle: { width: 1, color: '#f56c6c' },
              label: { show: false }
            },
            {
              yAxis: yAxisData[2],
              lineStyle: { width: 1, color: '#e6a23c' },
              label: { show: false }
            },
            {
              yAxis: yAxisData[3],
              lineStyle: { width: 1, color: '#333' },
              label: { show: false }
            },
            {
              yAxis: yAxisData[4],
              lineStyle: { width: 1, color: '#e6a23c' },
              label: { show: false }
            },
            {
              yAxis: yAxisData[5],
              lineStyle: { width: 1, color: '#f56c6c' },
              label: { show: false }
            }
          ]
        }
      },
      {
        type: 'bar',
        stack: 'Total',
        silent: true,
        itemStyle: {
          borderColor: 'transparent',
          color: 'transparent'
        },
        emphasis: {
          itemStyle: {
            borderColor: 'transparent',
            color: 'transparent'
          }
        },
        data: minData,
        yAxisIndex: 0
      },
      {
        type: 'bar',
        stack: 'Total',
        barWidth: '3px',
        data: seriesData,
        color: '#82e700',
        yAxisIndex: 0
      },
      {
        name: 'max',
        type: 'scatter',
        symbolSize: 6,
        data: maxScatterData,
        color: '#46b830',
        yAxisIndex: 0
      },
      {
        name: 'min',
        type: 'scatter',
        symbolSize: 6,
        data: minScatterData,
        color: '#46b830',
        yAxisIndex: 0
      }
    ]
  };

  myChart.setOption(option, true); //第二个参数 true 用来清除上次数据
}

function formatter(params, ticket, callback) {
  let str = params[0].data.n + '<br />时间：' + formatDateTime(params[0].data.qcDate, 'yyyy-MM-dd');

  for (let i = 0; i < params.length; i++) {
    if (!IsEmpty(params[i].data) && params[i].seriesType !== 'bar') {
      str += '<div>';
      str +=
        '<span style="display:inline-block;margin-right:5px;border-radius:10px;width:10px;height:10px;background-color:' +
        params[i].color +
        ';"></span>' +
        params[i].seriesName +
        '：';

      str +=
        '<span style="font-weight:bold;display: inline-block;width: 60px;margin-right:8px;">' +
        (params[i].seriesType === 'scatter' ? params[i].value[1] : params[i].value) +
        '</span>';

      str += '</div>';
    }
  }
  return str;
}
</script>
<style lang="scss" scoped>
#iqcMonicaChart {
  height: 100%;
  :deep(.vxe-modal--wrapper) {
    p {
      font-size: 1.2em;
      line-height: 1.8em;
    }
  }
}
</style>
<style lang="scss" scoped>
#QcMonicaChart {
  height: 100%;
  .bottomTable {
    height: 100%;
  }
  #monicachart {
    width: 100%;
    height: auto;
  }
  .iqcOutControlChart {
    .el-drawer__body {
      .iqcOutControl {
        width: 800px;
        margin: 0 auto;
      }
    }
  }
}
</style>
